﻿using Core.Info;
using Core.Utility;
using Core.Utility.Crypto;
using Core.Utility.Crypto.Core;
using Core.Utility.Helper;
using Core.ValidateRules.Lib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

/*
 * @生成日期 : 2022-11-10
 * @生成说明 : 应用配置
 */
namespace Dto.Core.Config
{
    /// <summary>
    /// 应用配置 , 表： app_config
    /// </summary>
    public class AppConfigDto : BaseDto
    {
        static AppConfigDto()
        {
            aes256Provider.OutType = OutType.Base64;
        }

        /// <summary>
        /// 配置文件存储路径
        /// </summary>
        public static readonly string FilePath = Path.Combine(AppInfo.ConfigDirectory, "app.config.json");

        /// <summary>
        /// aes256加密规则提供器
        /// </summary>
        private static ISymmetricProvider aes256Provider = CryptoFactory.CreateSymmetric(SymmetricProviderType.AES256);

        /// <summary>
        /// AES加密的Key
        /// </summary>
        private const string AesKey = @"loCFDPtTxTNxW5rR9zXTxIWWeXurxoRjYe2p0Al9FALtsJTuJm05BtUtivB2IMten4hm80LduJyHSnIu";

        /// <summary>
        /// AES,IV
        /// </summary>
        private const string AesIV = @"k5QxQdt55EDrSHQXXRNHO85Q1uY7f5";

        #region 属性

        #region 机构名称
        /// <summary>
        /// 机构名称
        /// </summary>
        private string? orgName;

        /// <summary>
        /// 机构名称
        /// </summary>
        [JsonProperty("org_name")]
        [Display(Name = "机构名称")]
        public string? OrgName
        {
            get { return orgName; }
            set
            {
                orgName = value;
                OnPropertyChanged();
            }
        }
        #endregion 机构名称

        #region 机构编码
        /// <summary>
        /// 机构编码
        /// </summary>
        private string? orgCode;

        /// <summary>
        /// 机构编码
        /// </summary>
        [JsonProperty("org_code")]
        [Display(Name = "机构编码")]
        public string? OrgCode
        {
            get { return orgCode; }
            set
            {
                orgCode = value;
                OnPropertyChanged();
            }
        }
        #endregion 机构编码

        #region api地址
        /// <summary>
        /// api地址
        /// </summary>
        private string? apiAddress;

        /// <summary>
        /// api地址
        /// </summary>
        [JsonProperty("api_address")]
        [Display(Name = "api地址")]
        public string? ApiAddress
        {
            get { return apiAddress; }
            set
            {
                apiAddress = value;
                OnPropertyChanged();
            }
        }
        #endregion api地址

        #region app_id
        /// <summary>
        /// app_id
        /// </summary>
        private string? appId;

        /// <summary>
        /// app_id
        /// </summary>
        [JsonProperty("app_id")]
        [Display(Name = "app_id")]
        public string? AppId
        {
            get { return appId; }
            set
            {
                appId = value;
                OnPropertyChanged();
            }
        }
        #endregion app_id

        #region app_key
        /// <summary>
        /// app_key
        /// </summary>
        private string? appKey;

        /// <summary>
        /// app_key
        /// </summary>
        [JsonProperty("app_key")]
        [Display(Name = "app_key")]
        public string? AppKey
        {
            get { return appKey; }
            set
            {
                appKey = value;
                OnPropertyChanged();
            }
        }
        #endregion app_key

        #region app_security
        /// <summary>
        /// app_security
        /// </summary>
        private string? appSecurity;

        /// <summary>
        /// app_security
        /// </summary>
        [JsonProperty("app_secret")]
        [Display(Name = "app_secret")]
        public string? AppSecret
        {
            get { return appSecurity; }
            set
            {
                appSecurity = value;
                OnPropertyChanged();
            }
        }
        #endregion app_security

        #region 消息体加密秘钥

        /// <summary>
        /// 消息体加密秘钥
        /// 长度固定为 43 个字符，从 a-z,A-Z,0-9 共 62 个字符中选取
        /// </summary>
        private string? _encodingAESKey;

        /// <summary>
        /// 消息体加密秘钥
        /// 长度固定为 43 个字符，从 a-z,A-Z,0-9 共 62 个字符中选取
        /// </summary>
        [JsonProperty("encoding_aes_key")]
        [Display(Name = "EncodingAESKey")]
        public string? EncodingAESKey
        {
            get { return _encodingAESKey; }
            set { SetProperty(ref _encodingAESKey, value); }
        }

        #endregion 消息体加密秘钥 

        #region 启用数据加密
        private bool _enabledDataEncrypt = true;

        /// <summary>
        /// 启用数据加密
        /// </summary>
        [JsonProperty("enabled_data_encrypt")]
        [Display(Name = "启用数据加密")]
        public bool EnabledDataEncrypt
        {
            get { return _enabledDataEncrypt; }
            set { SetProperty(ref _enabledDataEncrypt, value); }
        }
        #endregion 启用数据加密

        #region 令牌
        /// <summary>
        /// 令牌
        /// </summary>
        private string? token;

        /// <summary>
        /// 令牌
        /// </summary>
        [JsonProperty("token")]
        [Display(Name = "令牌")]
        public string? Token
        {
            get { return token; }
            set
            {
                token = value;
                OnPropertyChanged();
            }
        }
        #endregion 令牌

        #endregion 属性

        #region 方法

        /// <summary>
        /// 保存至配置文件(保存的数据将进行加密)
        /// </summary>
        /// <param name="appConfig"></param>
        /// <returns></returns>
        public static ReturnResultInfo<Exception> SaveToConfigFile(AppConfigDto appConfig)
        {
            ReturnResultInfo<Exception> res = new ReturnResultInfo<Exception>();
            try
            {
                appConfig.OrgCode = Encrypt(appConfig.OrgCode, nameof(appConfig.OrgCode));
                appConfig.OrgName = Encrypt(appConfig.OrgName, nameof(appConfig.OrgName));
                appConfig.ApiAddress = Encrypt(appConfig.ApiAddress, nameof(appConfig.ApiAddress));
                appConfig.AppId = Encrypt(appConfig.AppId, nameof(appConfig.AppId));
                appConfig.AppSecret = Encrypt(appConfig.AppSecret, nameof(appConfig.AppSecret));
                appConfig.AppKey = Encrypt(appConfig.AppKey, nameof(appConfig.AppKey));
                appConfig.Token = Encrypt(appConfig.Token, nameof(appConfig.Token));
                appConfig.EncodingAESKey = Encrypt(appConfig.EncodingAESKey, nameof(appConfig.EncodingAESKey));
                appConfig.EnabledDataEncrypt = appConfig.EnabledDataEncrypt;
                
                res = FileHelper.WriteFile(FilePath, JsonHelper.Serialize(appConfig));
            }
            catch(Exception ex)
            {
                res.SetException("保存AppConfig至配置文件出错", ex);
            }
            return res;
        }

        /// <summary>
        /// 加载自配置文件(加载的数据将进行解密)
        /// </summary>
        /// <returns></returns>
        public static ReturnResultInfo<AppConfigDto> LoadByConfigFile()
        {
            ReturnResultInfo<AppConfigDto> res = new ReturnResultInfo<AppConfigDto>();
            try
            {
                string? fileJosn = FileHelper.ReadFileToString(FilePath);
                var appConfig = JsonHelper.Deserialize<AppConfigDto>(fileJosn);
                if (appConfig != null)
                {
                    appConfig.OrgCode = Decrypt(appConfig.OrgCode, nameof(appConfig.OrgCode));
                    appConfig.OrgName = Decrypt(appConfig.OrgName, nameof(appConfig.OrgName));
                    appConfig.ApiAddress = Decrypt(appConfig.ApiAddress, nameof(appConfig.ApiAddress));
                    appConfig.AppId = Decrypt(appConfig.AppId, nameof(appConfig.AppId));
                    appConfig.AppSecret = Decrypt(appConfig.AppSecret, nameof(appConfig.AppSecret));
                    appConfig.AppKey = Decrypt(appConfig.AppKey, nameof(appConfig.AppKey));
                    appConfig.Token = Decrypt(appConfig.Token, nameof(appConfig.Token));
                    appConfig.EncodingAESKey = Decrypt(appConfig.EncodingAESKey, nameof(appConfig.EncodingAESKey));
                    appConfig.EnabledDataEncrypt = appConfig.EnabledDataEncrypt;
                }
                else
                {
                    appConfig = new AppConfigDto();
                }
                res.SetSuccess(appConfig);
            }
            catch (Exception ex)
            {
                res.SetException("保存AppConfig至配置文件出错", ex);
            }
            return res;
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="value">加密的原始值</param>
        /// <param name="propertyName">加密的属性名，用于加盐</param>
        /// <returns></returns>
        private static string? Encrypt(string? value, string? propertyName)
        {
            if (string.IsNullOrEmpty(value))
            {
                return value;
            }
            string aesKey = AesKey + propertyName;
            string aesIV = AesIV + propertyName;
            var aesEncryptRes = aes256Provider.Encrypt(value, aesKey, aesIV);
            return aesEncryptRes;
        }

        /// <summary>
        /// 解密,解密失败返回空字符串
        /// </summary>
        /// <param name="value">解密的原始值</param>
        /// <param name="propertyName">解密的属性名，用于加盐解密</param>
        /// <returns></returns>
        private static string? Decrypt(string? value, string? propertyName)
        {
            if (string.IsNullOrEmpty(value))
            {
                return value;
            }
            try
            {
                string aesKey = AesKey + propertyName;
                string aesIV = AesIV + propertyName;
                var aesEncryptRes = aes256Provider.Decrypt(value, aesKey, aesIV);
                return aesEncryptRes;
            }
            catch
            {
                return "";
            }
        }
        #endregion
    }
}